package bbs.service.impl;


import bbs.entity.config.WebConfig;
import bbs.entity.enums.ResponseCodeEnum;
import bbs.exception.BusinessException;
import bbs.service.AbstractTongYiServiceImpl;
import bbs.service.TongYiService;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.utils.Constants;
import io.reactivex.Flowable;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;

@Slf4j
@Service
public class TongYiSimpleServiceImpl extends AbstractTongYiServiceImpl {

    private static final Logger logger = LoggerFactory.getLogger(TongYiService.class);

    @Autowired
    private WebConfig webConfig;

    private String message;
    private String imageUrl;

    /**
     * 使用流式调用并 带回调的方式进行 消息生成
     *
     * @param gen
     * @param userMsg
     * @return
     * @throws NoApiKeyException
     * @throws ApiException
     * @throws InputRequiredException
     */
    @Override
    public Flux<ServerSentEvent<String>> streamCallWithMessage(Generation gen, Message userMsg)
            throws NoApiKeyException, ApiException, InputRequiredException {
        // 根据用户消息构建生成参数
        GenerationParam param = buildGenerationParam(userMsg);

        // 使用构建的参数启动生成调用，并返回生成结果的Flowable对象
        Flowable<GenerationResult> result = gen.streamCall(param);

        // 从结果创建一个Flux流
        Flux<ServerSentEvent<String>> serverSentEventFlux = Flux.from(result)
                .delayElements(Duration.ofMillis(100))
                // 处理每个消息事件
                .map(message -> {
                    // 提取消息内容
                    String output = message.getOutput().getChoices().get(0).getMessage().getContent();
                    logger.info("output = {}", output);
                    // 构建并返回ServerSentEvent对象
                    return ServerSentEvent.<String>builder()
                            .data(output)
                            .build();
                })
                // 添加事件("done") 用来触发结束处理的事件
                .concatWith(Flux.just(ServerSentEvent.<String>builder().event("done").build()))
                // 错误处理
                .doOnError(e -> {
                    // 根据不同类型的异常进行相应处理
                    if (e instanceof NoApiKeyException) {
                        throw new BusinessException(ResponseCodeEnum.CODE_700);
                    } else if (e instanceof InputRequiredException) {
                        throw new BusinessException(ResponseCodeEnum.CODE_701);
                    } else if (e instanceof ApiException) {
                        throw new BusinessException(ResponseCodeEnum.CODE_702);
                    } else {
                        throw new BusinessException(ResponseCodeEnum.CODE_500);
                    }
                });

        return serverSentEventFlux;
    }

    @Override
    public MultiModalConversationResult readImage(String message, String imageUrl) throws NoApiKeyException, UploadFileException {
        this.message = message;
        this.imageUrl = imageUrl;
        MultiModalConversationResult result = simpleMultiModalConversationCall();
        return result;
    }

    @Override
    public MultiModalConversationResult notStream(String message) throws NoApiKeyException, UploadFileException {
        this.message = message;
        return summarizeCall();
    }


    public MultiModalConversationResult simpleMultiModalConversationCall() throws NoApiKeyException, UploadFileException {
        // 设置API密钥
        Constants.apiKey = webConfig.getApiKey();

        MultiModalConversation conv = new MultiModalConversation();

        MultiModalMessage userMessage = MultiModalMessage.builder()
                .role(Role.USER.getValue())
                .content(Arrays.asList(Collections.singletonMap("image", imageUrl),
                        Collections.singletonMap("text", message)))
                .build();

        MultiModalConversationParam param = MultiModalConversationParam.builder()
                .model(MultiModalConversation.Models.QWEN_VL_PLUS)
                .message(userMessage)
                .build();
        MultiModalConversationResult result = conv.call(param);
        logger.info(String.valueOf(result));
        return result;
    }

    public MultiModalConversationResult summarizeCall() throws NoApiKeyException, UploadFileException {
        // 设置API密钥
        Constants.apiKey = webConfig.getApiKey();

        MultiModalConversation conv = new MultiModalConversation();

        MultiModalMessage userMessage = MultiModalMessage.builder()
                .role(Role.USER.getValue())
                .content(Arrays.asList(Collections.singletonMap("text", message)))
                .build();

        MultiModalConversationParam param = MultiModalConversationParam.builder()
                .model(MultiModalConversation.Models.QWEN_VL_PLUS)
                .message(userMessage)
                .build();
        MultiModalConversationResult result = conv.call(param);
        logger.info(String.valueOf(result));
        return result;
    }

    private GenerationParam buildGenerationParam(Message userMsg) {
        return GenerationParam.builder()
                .model("qwen-max")
                .messages(Arrays.asList(userMsg))
                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                .topP(0.8)
                .incrementalOutput(true)
                .build();
    }

}